package com.jumi.microservice.controller.api;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jm.member.common.core.exception.BaseException;
import com.jm.member.common.core.utils.ServletUtils;
import com.jm.member.common.core.utils.ip.IpUtils;
import com.jm.member.common.jwt.annon.IgnoreUrlsAnnon;
import com.jm.member.common.jwt.constant.JwtAdminInfo;
import com.jm.member.common.jwt.util.JwtTokenUtil;
import com.jm.member.common.messages.entity.JiGuangResponse;
import com.jm.member.common.messages.entity.WeChartUserInfo;
import com.jm.member.common.messages.service.AliMessageService;
import com.jm.member.common.messages.service.WeChartService;
import com.jm.member.common.messages.util.JiGuangUtil;
import com.jm.member.common.redis.service.RedisService;
import com.jumi.microservice.common.base.dto.ResponseResult;
import com.jumi.microservice.dto.reponse.api.LoginResponse;
import com.jumi.microservice.entity.JmJpushUser;
import com.jumi.microservice.entity.JmUser;
import com.jumi.microservice.enums.CommonEnum;
import com.jumi.microservice.enums.MessageType;
import com.jumi.microservice.enums.SourceType;
import com.jumi.microservice.service.IJmJpushUserService;
import com.jumi.microservice.service.IJmUserService;
import com.jumi.microservice.util.MessageUtil;
import com.jumi.microservice.util.PasswordUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Component
public class LoginController {

    protected static final Logger logger = LoggerFactory.getLogger(LoginController.class);


    @Resource
    AliMessageService messageService;

    @Resource
    RedisService redisService;

    @Resource
    IJmUserService userService;


    @Resource
    WeChartService weChartService;


    @PostMapping("/sendSms")
    @IgnoreUrlsAnnon("/sendSms")
    @ApiOperation("发送短信--继承接口")
    public ResponseResult sendSms(@ApiParam(required = true, value = "手机号") @RequestParam String mobile,
                                  @ApiParam(required = true, value = "发送类型") @RequestParam MessageType type) {
        return ResponseResult.success(MessageUtil.sendSms(messageService, redisService, type.getValue(), mobile));
    }

    //messageLogin
    @PostMapping("/CheckSms")
    @IgnoreUrlsAnnon("/CheckSms")
    @ApiOperation("短信验证--继承接口")
    public ResponseResult CheckSms(@ApiParam(required = true, value = "手机号") @RequestParam String mobile,
                                   @ApiParam(required = true, value = "验证码") @RequestParam String code,
                                   @ApiParam(required = true, value = "发送类型") @RequestParam MessageType type) {
        MessageUtil.checkCode(code, redisService, type.getValue() + mobile);
        //String token = mobileLogin(mobile);
        return ResponseResult.success();
    }

    //messageLogin
    @PostMapping("/messageLogin")
    @IgnoreUrlsAnnon("/messageLogin")
    @ApiOperation("短信验证码登录--继承接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inviterId", value = "邀请人id"),
            @ApiImplicitParam(name = "registerId", value = "registerId")
    })
    public ResponseResult messageLogin(@ApiParam(required = true, value = "手机号") @RequestParam String mobile,
                                       @ApiParam(required = true, value = "验证码") @RequestParam String code,
                                       String inviterId, String registerId) {
        Long memberInviterId = (inviterId != null && inviterId.length() != 0) ? Long.parseLong(inviterId) : 0;
        MessageUtil.checkCode(code, redisService, MessageType.登录验证.getValue() + mobile);
        LoginResponse response = mobileLogin(mobile, memberInviterId, registerId);
        return ResponseResult.success(response);
    }

    @PostMapping("/passwordLogin")
    @IgnoreUrlsAnnon("/passwordLogin")
    @ApiOperation("用户名密码登录--继承接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inviterId", value = "邀请人id"),
            @ApiImplicitParam(name = "registerId", value = "registerId")
    })
    public ResponseResult passwordLogin(@ApiParam(required = true, value = "手机号") @RequestParam String mobile,
                                        @ApiParam(required = true, value = "密码") @RequestParam String passWord,
                                        String inviterId, String registerId) {
        Long memberInviterId = (inviterId != null && inviterId.length() != 0) ? Long.parseLong(inviterId) : 0;
        JmUser userByMobile = userService.getUserByMobile(mobile);
        String passwd = PasswordUtils.passwd(passWord);
        if (ObjectUtil.isEmpty(userByMobile)) {
            return ResponseResult.error("用户未注册!");
        }
        if (passwd.equals(userByMobile.getPasswd())) {
            LoginResponse response = login(userByMobile, memberInviterId, registerId);
            return ResponseResult.success(response);
        }
        return ResponseResult.error("用户名或密码错误!");
    }


    @PostMapping("/loginWeChart")
    @IgnoreUrlsAnnon("/loginWeChart")
    @ApiOperation("微信登录--继承接口")
    @ApiImplicitParams(
            {@ApiImplicitParam(name = "token", value = "运营商下发的token"),
                    @ApiImplicitParam(name = "code", value = "验证码"),
                    @ApiImplicitParam(name = "inviterId", value = "邀请人id"),
                    @ApiImplicitParam(name = "registerId", value = "registerId"),
                    @ApiImplicitParam(name = "mobile", value = "手机号"),
                    @ApiImplicitParam(name = "token", value = "微信令牌")
            }
    )
    public ResponseResult loginWeChart(@Validated WeChartUserInfo weChartUserInfo, String mobile,
                                       String token, String code, String inviterId, String registerId) {
        Long memberInviterId = (inviterId != null && inviterId.length() != 0) ? Long.parseLong(inviterId) : 0;
        if (ObjectUtil.isAllNotEmpty(token, code) || ObjectUtil.isAllEmpty(token, code)) {
            return ResponseResult.error("选择正确的认证方式!");
        } else if (ObjectUtil.isNotEmpty(code)) {
            //验证码
            CheckSms(mobile, code, MessageType.登录验证);
        } else if (ObjectUtil.isNotEmpty(token)) {
            //验证手机号
            JiGuangResponse response = JiGuangUtil.loginTokenVerify(token);
            //极光返回的解密后的手机号
            if (!response.getCode().equals(JiGuangResponse.successLoginTokenCode)) {
                return ResponseResult.error(500, "验证手机号失败!", response);
            }
            mobile = JiGuangUtil.decode(response.getPhone());
        }
        ResponseResult rs = loginWeChartBinding(weChartUserInfo, mobile, memberInviterId, registerId);
        return rs;
    }


    public ResponseResult loginWeChartBinding(WeChartUserInfo weChartUserInfo,
                                              String mobile,
                                              Long inviterId, String registerId) {
        JmUser userByMobile = userService.getUserByMobile(mobile);
        //微信登录绑定时如果没有记录，生成一条。如果有记录，没有微信信息 填充微信信息更新。
        if (ObjectUtil.isNotEmpty(userByMobile) && ObjectUtil.isNotEmpty(userByMobile.getWxOpenid())) {
            return ResponseResult.error("此手机已经绑定微信!");
        }
        if (ObjectUtil.isEmpty(userByMobile)) {
            userByMobile = new JmUser();
            userByMobile.setMobile(mobile);
        }
        userByMobile.setAvatar(weChartUserInfo.getHeadimgurl());
        userByMobile.setWxOpenid(weChartUserInfo.getOpenid());
        userByMobile.setWeixinUnionid(weChartUserInfo.getUnionid());
        LoginResponse response = login(userByMobile, inviterId, registerId);
        return ResponseResult.success(response);
    }


    /**
     * @param unionId 微信unionId
     *                判断微信是否绑定用户
     */
    public JmUser checkExistByUnionId(String unionId) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("weixin_unionid", unionId);
        JmUser user = userService.getOne(wrapper);
        return user;
    }

    public JmUser checkExistByIOSId(String iosId) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("ios_sign_id", iosId);
        JmUser user = userService.getOne(wrapper);
        return user;
    }

    public void deleteOpenId(String openid) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("wx_openid", openid);
        JmUser user = userService.getOne(wrapper);
        if (ObjectUtil.isNotEmpty(user)) {
            user.setWxOpenid("");
            userService.updateById(user);
        }
    }


    public LoginResponse mobileLogin(String mobile, Long inviterId, String registerId) {
        JmUser userByMobile = userService.getUserByMobile(mobile);
        if (ObjectUtil.isEmpty(userByMobile)) {
            userByMobile = new JmUser();
            userByMobile.setMobile(mobile);
        }
        return login(userByMobile, inviterId, registerId);
    }

    @Autowired
    IJmJpushUserService JpushUserService;

    /**
     * @param user
     * @param inviterId  邀请人id
     * @param registerId
     * @return
     */
    public LoginResponse login(JmUser user, Long inviterId, String registerId) {
        String client = ServletUtils.getStrHeader(JwtAdminInfo.loginClient);//注册的客户端
        String model = ServletUtils.getStrHeader(JwtAdminInfo.loginModel);//注册时的手机型号
        if (!isFullUser(user)) {
            String mobile = user.getMobile();
            MessageUtil.checkMobile(mobile);
            user.setPasswd(PasswordUtils.passwd("123456"));
            user = userService.packUser(user);
            user.setClient(client);
            user.setModel(model);
            user.setAvatar("http://img.jumituangou.com/clientUse/public/defaultimg.png");
            userService.saveUser(user);
            if (ObjectUtil.isNotEmpty(inviterId)) {
                bindInviter(user, inviterId);//添加用户时,去绑定上级
            }
        }
        if (ObjectUtil.isNotEmpty(registerId)) {
            updateJg(user, registerId, client);
        }
        return doLogin(user, client, model,registerId);
    }

    /**
     * 更新登录的极光推送信息
     */
    public void updateJg(JmUser jmUser, String registerId, String client) {
        JmJpushUser jgPush = JpushUserService.getJgPushByRegisterId(registerId,jmUser.getId());
        if (ObjectUtil.isEmpty(jgPush)) {
            jgPush = new JmJpushUser();
        }
        jgPush.setRegisterTime(LocalDateTime.now());
        jgPush.setUid(jmUser.getId());
        jgPush.setMobile(jmUser.getMobile());
        jgPush.setClient(client);
        jgPush.setRegisterId(registerId);
        jgPush.setStatus(1);
        JpushUserService.saveOrUpdate(jgPush);
    }

    /**
     * 绑定邀请人
     */
    public void bindInviter(JmUser user, Long inviterId) {
        Long getInviterId = inviterId / 999999999;   //处理前端加密id
        JmUser inviterUser = userService.getById(getInviterId);//邀请人
        if (ObjectUtil.isNotEmpty(inviterUser)) {
            userService.bindUp(user, inviterUser, SourceType.填写邀请码);
        }
    }


    public LoginResponse doLogin(JmUser user, String client, String model,String registerId) {
        String ipAddr = IpUtils.getIpAddr(ServletUtils.getRequest());
        CommonEnum allowLogin = user.getAllowLogin();
        if (allowLogin.equals(CommonEnum.否)) {
            throw new BaseException(500, "此用户禁止登录!");
        }
        user.setLoginIp(ipAddr);
        user.setLastLoginClient(client);
        user.setLoginTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setLastLoginModel(model);
        userService.updateById(user);
        LoginResponse response = new LoginResponse();
        String token = genToken(user,registerId);
        response.setToken(token);
        response.setAvatar(user.getAvatar());
        response.setLevel(user.getLevel());
        response.setMobile(user.getMobile());
        response.setName(user.getName());
        response.setTruename(user.getTruename());
        response.setSex(user.getSex());
        response.setUid(user.getId());
        response.setWxOpenid(user.getWxOpenid());
        return response;
    }


    public boolean isFullUser(JmUser user) {
        return ObjectUtil.isAllNotEmpty(user.getMobile(), user.getPasswd(), user.getName(), user.getCreateTime(), user.getCode());
    }


    private String createTokenKey(Integer uid) {
        StringBuffer keyBuffer = new StringBuffer();
        String UUID = IdUtil.fastSimpleUUID();
        keyBuffer.append(uid).append("-").append(UUID);
        String keyWords = keyBuffer.toString();
        return keyWords;
    }

    public String genToken(JmUser user,String registerId) {

        String keyWords = this.createTokenKey(user.getId());
        String tokenKey = StrUtil.format("{}{}", JwtTokenUtil.prefix, keyWords);

        String token = redisService.getCacheObject(tokenKey);
        if (StrUtil.isEmpty(token)) {
            Map map = new HashMap();
            map.put(JwtAdminInfo.apiUserId, user.getId());
            map.put(JwtAdminInfo.apiName, user.getName());
            map.put(JwtAdminInfo.apiMobile, user.getMobile());
            map.put(JwtAdminInfo.tokenKey, tokenKey);
            map.put(JwtAdminInfo.jpushRegisterId,registerId);
            token = JwtTokenUtil.generateToken(map);
            redisService.setCacheObject(tokenKey, token);//token存储redis
        }
        return token;
    }

    //    获取小程序手机号
    public Object getPhoneNumber(String encryptedData, String session_key, String iv) {
        // 被加密的数据
        byte[] dataByte = Base64.decode(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.decode(session_key);
        // 偏移量
        byte[] ivByte = Base64.decode(iv);
        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                return JSONObject.parseObject(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
